/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nytimes.ohos.store.sample.slice;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.nytimes.ohos.external.fs3.SourcePersisterFactory;
import com.nytimes.ohos.external.store3.base.Fetcher;
import com.nytimes.ohos.external.store3.base.Persister;
import com.nytimes.ohos.external.store3.base.impl.BarCode;
import com.nytimes.ohos.external.store3.base.impl.MemoryPolicy;
import com.nytimes.ohos.external.store3.base.impl.Store;
import com.nytimes.ohos.external.store3.base.impl.StoreBuilder;
import com.nytimes.ohos.external.store3.middleware.GsonParserFactory;
import com.nytimes.ohos.store.sample.HmSchedulers;
import com.nytimes.ohos.store.sample.ListAdapter;
import com.nytimes.ohos.store.sample.MyApplication;

import com.nytimes.ohos.store.sample.ResourceTable;
import com.nytimes.ohos.store.sample.data.model.Children;
import com.nytimes.ohos.store.sample.data.model.GsonAdaptersModel;
import com.nytimes.ohos.store.sample.data.model.Post;
import com.nytimes.ohos.store.sample.data.model.RedditData;
import com.nytimes.ohos.store.sample.data.remote.Api;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Single;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import okhttp3.ResponseBody;
import okio.BufferedSource;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class PersistingStoreAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
    }

    private void initStore() {
        BarCode awwRequest = new BarCode(RedditData.class.getSimpleName(), "aww");
        try {
            providePersistedRedditStore()
                    .get(awwRequest)
                    .flatMapObservable(new Function<RedditData, ObservableSource<Post>>() {
                        @Override
                        public ObservableSource<Post> apply( RedditData redditData) throws Exception {
                            return sanitizeData(redditData);
                        }
                    })
                    .toList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(HmSchedulers.mainThread())
                    .subscribe(this::showPosts, throwable -> {
                        System.out.println("========="+throwable.getMessage());
                    });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void showPosts(List<Post> list) {
        ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list);
        ListAdapter listAdapter = new ListAdapter(list, getContext());
        listContainer.setItemProvider(listAdapter);
    }
    private Observable<Post> sanitizeData(RedditData redditData) {
        return Observable.fromIterable(redditData.data().children())
                .map(Children::data);
    }
    @Override
    public void onActive() {
        super.onActive();
        initStore();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    /**
     * Provides a Store which will persist RedditData to the cache, and use Gson to parse the JSON
     * that comes back from the network into RedditData.
     *
     * @return  Store<RedditData, BarCode>
     * @throws IOException
     */
    private Store<RedditData, BarCode> providePersistedRedditStore() throws IOException {
        return StoreBuilder.parsedWithKey()
                .fetcher(new nonmFetch())
                .persister(newPersister())
                .parser(GsonParserFactory.createSourceParser(provideGson(), RedditData.class))
                .open();
    }


    private class nonmFetch<Raw, Key> implements Fetcher<BufferedSource, BarCode> {

        @Override
        public Single<BufferedSource> fetch(BarCode barCode) {
            return fetcher(barCode);
        }
    }


    /**
     * Returns a "fetcher" which will retrieve new data from the network.
     *
     * @param barCode BarCode
     * @return  Single<BufferedSource>
     */
    private Single<BufferedSource> fetcher(BarCode barCode) {
        return provideRetrofit().fetchSubredditForPersister(barCode.getKey(), "10")
                .map(new mFuction());
    }

    private static final class mFuction implements Function<ResponseBody, BufferedSource> {
        @Override
        public BufferedSource apply(ResponseBody responseBody) throws Exception {
            return responseBody.source();
        }
    }

    private Api provideRetrofit() {
        return new Retrofit.Builder()
                .baseUrl("http://reddit.com/")
                .addConverterFactory(GsonConverterFactory.create(provideGson()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(Api.class);
    }

    private Gson provideGson() {
        return new GsonBuilder()
                .registerTypeAdapterFactory(new GsonAdaptersModel())
                .create();
    }

    /**
     * Returns a new Persister with the cache as the root.
     *
     * @return  Persister<BufferedSource, BarCode>
     * @throws IOException
     */
    private Persister<BufferedSource, BarCode> newPersister() throws IOException {
        return SourcePersisterFactory.create(getExternalCacheDir());
    }
}
